/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.zhanghai.harmony.materialprogressbar;

import me.zhanghai.harmony.materialprogressbar.util.LogUtil;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

/**
 * class MaterialDeterminateProgressBar
 */
public class MaterialDeterminateProgressBar extends Component implements Component.DrawTask {
    private static final int SWEEP_ANGLE = 360;

    private static final int MAX_ANGLE = 720;

    private static final int PAINT_COLOR = Color.getIntColor("#196F3D");

    private static final int LTGRAY = 0xffcccccc;

    private static final int DKGRAY = 0xff444444;

    private static final int TINTED = Color.getIntColor("#FF6600");

    private static final int NORMAL_PROGRESS = 36;

    private static final int START_ANGLE = 270;

    private static final int SLEEP_TIME = 1000;

    private static final float DIV = 2.0f;

    private static final String TAG = "MaterialDeterminateProgressBar";

    private static final String PROGRESSBAR_STYLE = "progressbar_style";

    private static final String PROGRESSBAR_TYPE = "progressbar_type";

    private static final String PROGRESSBAR_TINTED = "progressbar_tinted";

    private static final String PROGRESSBAR_COLOR = "progressbar_color";

    private static final String TYPE_PRIMARY = "primary";

    private static final String TYPE_SECONNDARY = "secondary";

    private static final String TYPE_BACKGROUND = "background";

    private static final String PROGRESSBAR_WIDTH = "progressbar_width";

    private static final String ATTR = "vp";

    private static int STROKE_WIDTH = 10;

    private final EventHandler mNormalHandler = new EventHandler(EventRunner.getMainEventRunner());

    private AttrSet attrSet;

    private String progressbarStyle;

    private String progressbarType;

    private String progressbarTinted;

    private String progressbarColor;

    private Paint mPaint;

    private int normalProgressStatus = 0;

    private int dynamicProgressStatus = 0;

    private int zero = 0;

    private RectFloat rectFloat;

    private RectFloat rectFloatDynamic;

    private Arc arcBackground;

    private Arc arcSecondary;

    private Arc arc;

    private Arc arcBackgroundDynamic;

    private Arc arcSecondaryDynamic;

    private Arc arcDynamic;

    private boolean status;

    private String typeNormal = "normal";

    private String typeDynamic = "dynamic";

    public MaterialDeterminateProgressBar(Context context) {
        super(context);
    }

    public MaterialDeterminateProgressBar(Context context, AttrSet attrSet) {
        super(context, attrSet);
        this.attrSet = attrSet;
        init();
    }

    public MaterialDeterminateProgressBar(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        this.attrSet = attrSet;
        init();
    }

    private void init() {
        int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
        int sideLength = Math.min(availableWidth, availableHeight);

        float left = getPaddingLeft() + (availableWidth - sideLength) / DIV;
        float top = getPaddingTop() + (availableHeight - sideLength) / DIV;

        // left, float top, float right, float bottom
        rectFloat = new RectFloat(left, top, left + sideLength, top + sideLength);
        arc = new Arc();
        arcSecondary = new Arc();
        arcBackground = new Arc();
        arcBackground.setArc(zero, SWEEP_ANGLE, false);

        rectFloatDynamic = new RectFloat(left, top, left + sideLength, top + sideLength);
        arcDynamic = new Arc();
        arcSecondaryDynamic = new Arc();
        arcBackgroundDynamic = new Arc();
        arcBackgroundDynamic.setArc(zero, SWEEP_ANGLE, false);

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE_STYLE);
        mPaint.setColor(new Color(PAINT_COLOR));
        mPaint.setAntiAlias(true);

        if (checkAttr(attrSet, PROGRESSBAR_WIDTH)) {
            STROKE_WIDTH = getStrokeWidth();
        }

        mPaint.setStrokeWidth(STROKE_WIDTH);
        addDrawTask(this);

        // Get attributes
        if (checkAttr(attrSet, PROGRESSBAR_STYLE)) {
            progressbarStyle = attrSet.getAttr(PROGRESSBAR_STYLE).get().getStringValue().trim();
        }

        if (checkAttr(attrSet, PROGRESSBAR_TYPE)) {
            progressbarType = attrSet.getAttr(PROGRESSBAR_TYPE).get().getStringValue().trim();
        }

        if (checkAttr(attrSet, PROGRESSBAR_TINTED)) {
            progressbarTinted = attrSet.getAttr(PROGRESSBAR_TINTED).get().getStringValue().trim();
        }

        if (checkAttr(attrSet, PROGRESSBAR_COLOR)) {
            progressbarColor = attrSet.getAttr(PROGRESSBAR_COLOR).get().getStringValue().trim();
        }

        // to check the progressbar style and start appropriate progressbar
        if (progressbarStyle.equalsIgnoreCase(typeNormal)) {
            startNormalProgress();
        } else if (progressbarStyle.equalsIgnoreCase(typeDynamic)) {
            startDynamicProgress();
        } else {
            LogUtil.info(TAG, "Unhandled Case");
        }
    }

    private int getStrokeWidth() {
        boolean isWidth = checkAttr(attrSet, PROGRESSBAR_WIDTH);
        if (isWidth) {
            String strokeValue = attrSet.getAttr(PROGRESSBAR_WIDTH).get().getStringValue();
            if (strokeValue.contains(ATTR)) {
                strokeValue = strokeValue.replace(ATTR, "");
            }
            STROKE_WIDTH = Integer.parseInt(strokeValue);
        }
        return STROKE_WIDTH;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        // cPaint object is used for non-tinted type progressbars
        Paint cPaint = new Paint();
        cPaint.setStyle(Paint.Style.STROKE_STYLE);
        cPaint.setColor(new Color(LTGRAY));
        cPaint.setAntiAlias(true);
        cPaint.setStrokeWidth(STROKE_WIDTH);

        // cPaint object is used for tinted type progressbars
        Paint vPaint = new Paint();
        vPaint.setStyle(Paint.Style.STROKE_STYLE);
        vPaint.setColor(new Color(DKGRAY));
        vPaint.setAntiAlias(true);
        vPaint.setStrokeWidth(STROKE_WIDTH);

        String tinStatus = "true";

        if (progressbarTinted.equalsIgnoreCase(tinStatus)) {
            mPaint.setColor(new Color(TINTED));
        }

        if (progressbarColor != null) {
            mPaint.setColor(new Color(Color.getIntColor(progressbarColor)));
        }

        if (progressbarStyle.equalsIgnoreCase(typeNormal)) {
            if (progressbarType.equalsIgnoreCase(TYPE_PRIMARY)) {
                canvas.drawArc(rectFloat, arc, mPaint);
            } else if (progressbarType.equalsIgnoreCase(TYPE_SECONNDARY)) {
                canvas.drawArc(rectFloat, arcSecondary, vPaint);
                canvas.drawArc(rectFloat, arc, mPaint);
            } else if (progressbarType.equalsIgnoreCase(TYPE_BACKGROUND)) {
                canvas.drawArc(rectFloat, arcBackground, cPaint);
                canvas.drawArc(rectFloat, arcSecondary, vPaint);
                canvas.drawArc(rectFloat, arc, mPaint);
            } else {
                LogUtil.info(TAG, "Unhandled Case");
            }
        } else if (progressbarStyle.equalsIgnoreCase(typeDynamic)) {
            if (progressbarType.equalsIgnoreCase(TYPE_PRIMARY)) {
                canvas.drawArc(rectFloatDynamic, arcDynamic, mPaint);
            } else if (progressbarType.equalsIgnoreCase(TYPE_SECONNDARY)) {
                canvas.drawArc(rectFloatDynamic, arcSecondaryDynamic, vPaint);
                canvas.drawArc(rectFloatDynamic, arcDynamic, mPaint);
            } else if (progressbarType.equalsIgnoreCase(TYPE_BACKGROUND)) {
                canvas.drawArc(rectFloatDynamic, arcBackgroundDynamic, cPaint);
                canvas.drawArc(rectFloatDynamic, arcSecondaryDynamic, vPaint);
                canvas.drawArc(rectFloatDynamic, arcDynamic, mPaint);
            } else {
                LogUtil.info(TAG, "Unhandled Case");
            }
        } else {
            LogUtil.info(TAG, "Unhandled Case");
        }
    }

    private void startNormalProgress() {
        new Thread(() -> {
            while (normalProgressStatus < SWEEP_ANGLE) {
                normalProgressStatus += NORMAL_PROGRESS;
                mNormalHandler.postTask(() -> {
                    arc.setArc(START_ANGLE, normalProgressStatus, false);
                    arcSecondary.setArc(START_ANGLE, normalProgressStatus + NORMAL_PROGRESS, false);
                    invalidate();

                    if (normalProgressStatus == SWEEP_ANGLE) {
                        normalProgressStatus = zero;
                    }
                });
                try {
                    // Sleep for SLEEP_TIME milliseconds.
                    // Just to display the progress slowly
                    Thread.sleep(SLEEP_TIME); // thread will take approx 1 seconds to finish
                } catch (InterruptedException e) {
                    LogUtil.error(TAG, "InterruptedException");
                }
            }
        }).start();
    }

    private void startDynamicProgress() {
        new Thread(() -> {
            while (dynamicProgressStatus < MAX_ANGLE) {
                dynamicProgressStatus += NORMAL_PROGRESS;
                mNormalHandler.postTask(() -> {
                    if (dynamicProgressStatus >= SWEEP_ANGLE) {
                        arcDynamic.setArc(START_ANGLE, dynamicProgressStatus, false);
                        arcSecondaryDynamic.setArc(START_ANGLE, dynamicProgressStatus + NORMAL_PROGRESS, false);
                    } else {
                        if (dynamicProgressStatus > NORMAL_PROGRESS) {
                            arcDynamic.setArc(dynamicProgressStatus, dynamicProgressStatus, false);
                            arcSecondaryDynamic.setArc(dynamicProgressStatus, dynamicProgressStatus + NORMAL_PROGRESS,
                                    false);
                        } else {
                            arcDynamic.setArc(zero, dynamicProgressStatus, false);
                            arcSecondaryDynamic.setArc(zero, dynamicProgressStatus + NORMAL_PROGRESS, false);
                        }
                    }
                    invalidate();
                    if (dynamicProgressStatus == MAX_ANGLE) {
                        dynamicProgressStatus = zero;
                    }
                });
                try {
                    // Sleep for 1000 milliseconds.
                    // Just to display the progress slowly
                    Thread.sleep(SLEEP_TIME); // thread will take approx 1.1 seconds to finish
                } catch (InterruptedException e) {
                    LogUtil.error(TAG, "InterruptedException");
                }
            }
        }).start();
    }

    private boolean checkAttr(AttrSet attrSet, String attrName) {
        return attrSet.getAttr(attrName).isPresent();
    }

}